SPDX-FileCopyrightText: 2018 Boris Bardonneau & Nestor Beguin SPDX-FileCopyrightText: 2024 AlICe laboratory https://alicelab.be
SPDX-License-Identifier: GPL-3.0-or-later
SETUP CAMERA AND MODEL CLEANING# ###go line 100 for code
import bpy
import random
from random import choice
for o in bpy.data.objects:  # nettoie aussi l'animation
    o.hide = False
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.delete(use_global=False)script realise sous Blender hach 4bb1e22 18.11.2016 par AlICelab CAMERA SCRIPT
import math
from math import radians
from math import cos
from math import sinDefinition de la fonction de création de camera en projection parallele
def axoCam(projection, canon):
    bpy.ops.object.camera_add()
    maScene = bpy.context.scene.render
    monAxoCam = bpy.context.object
    monAxoCam.data.type = "ORTHO"
    monAxoCam.data.ortho_scale = 30
    if projection == "axonometrique":
        if canon == "isometrie":  # OK
            monAxoCam.name = "axoIsometrie"
            monAxoCam.rotation_euler = (radians(54.74), 0.0, radians(45))
            monAxoCam.location = (10.0, -10.0, 10.0)
            maScene.pixel_aspect_x = 1
        if canon == "dimetrie":  # OK
            monAxoCam.name = "axoDimetrie"
            monAxoCam.rotation_euler = (radians(60), 0.0, radians(23))
            monAxoCam.location = (5.53, -13.04, 8.18)
            maScene.pixel_aspect_x = 1
        if canon == "trimetrie":  # OK
            monAxoCam.name = "axoTrimetrie"
            monAxoCam.rotation_euler = (radians(67), 0.0, radians(34))
            monAxoCam.location = (8.59, -12.734, 6.52)
            maScene.pixel_aspect_x = 1
    if projection == "oblique":
        if canon == "militaire":  # OK
            monAxoCam.name = "oblMilitaire"
            monAxoCam.rotation_euler = (radians(45), 0.0, radians(30))
            monAxoCam.location = (7.071, -12.247, 10 * 1 / cos(radians(45)))
            maScene.pixel_aspect_x = 1 / cos(radians(45))
        if canon == "militaireDiminuee":  # OK
            monAxoCam.name = "oblMilitaireDiminuee"
            monAxoCam.rotation_euler = (radians(45 * 0.82), 0.0, radians(30))
            monAxoCam.location = (5.309, -9.195, 10 * 1 / cos(radians(45)))
            maScene.pixel_aspect_x = 1 / cos(radians(45 * 0.82))
        if canon == "cavalierePlan":  # OK
            monAxoCam.name = "oblCavalierePlan"
            monAxoCam.rotation_euler = (radians(45), 0.0, radians(45))
            monAxoCam.location = (10.0, -10.0, 10 * 1 / cos(radians(45)))
            maScene.pixel_aspect_x = 1 / cos(radians(45))
        if canon == "cavalierePlanDiminuee":  # OK
            monAxoCam.name = "oblCavalierePlanDiminuee"
            monAxoCam.rotation_euler = (radians(45 * 0.82), 0.0, radians(45))
            monAxoCam.location = (7.5, -7.5, 10 * 1 / cos(radians(45)))
            maScene.pixel_aspect_x = 1 / cos(radians(45 * 0.82))
        if canon == "cavaliereAngleCam":  # OK mais à recentrer manuellement
            angleZ = radians(30)  # entrer l'angle de rotation de la camera en Z
            angleZ_XY = radians(
                15
            )  # entrer l'angle d'inclinaison de la camera par rapport au sol
            monAxoCam.name = "oblCavalierePlanDiminuee"
            monAxoCam.rotation_euler = (angleZ_XY, 0.0, angleZ)
            monAxoCam.location = (10, -10, 10 * 1 / cos(radians(45)))
            maScene.pixel_aspect_x = 1 / cos(angleZ_XY)Execution de la fonction de création de la camera choix du type de projection: Effacer le # devant la ligne pour choisir le type de camera à créer
PROJECTION OBLIQUE#
axoCam (‘oblique’,’militaire’) axoCam (‘oblique’,’militaireDiminuee’) axoCam (‘oblique’,’cavalierePlan’) axoCam (‘oblique’,’cavalierePlanDiminuee’) axoCam (‘oblique’,’cavaliereAngleCam’) #celle ci peut être réglée en angle de vue -> regarder dans la dernière formule
PROJECTION AXONOMETRIQUE#
axoCam("axonometrique", "isometrie")axoCam (‘axonometrique’,’dimetrie’) axoCam (‘axonometrique’,’trimetrie’)
DIMENSIONEMENT DE L’ENVELOPPE GENERALE ET DU CENTRE DU SOCLE ( CUBE )
Rectanglex = [10]
Rectangley = [10]
Rectangleposx = [5]
Rectangleposy = [5]def Division(x, y, px, py, i):  # SEGMENTATION DU SOCLE EN MUSICIENS
    choix = 1 if x > y else 0  # Détermine le plus grand rectangle de la liste
    if choix == 1:  # Segmente en x
        xvar = random.uniform(0, x)
        xvar2 = x - xvar
        yvar = y
        yvar2 = y
        posx = px - x / 2 + xvar / 2
        posy = py
        posx2 = px - x / 2 + xvar + xvar2 / 2
        posy2 = py
    else:  # Segmente en y
        yvar = random.uniform(0, y)
        yvar2 = y - yvar
        xvar = x
        xvar2 = x
        posx = px
        posy = py - y / 2 + yvar / 2
        posx2 = px
        posy2 = py - y / 2 + yvar + yvar2 / 2
    Rectanglex[i] = xvar  # Change la valeur du rectangle de base
    Rectangley[i] = yvar
    Rectangleposx[i] = posx
    Rectangleposy[i] = posy
    Rectanglex.append(xvar2)  # Ajoute le second rectangle créé
    Rectangley.append(yvar2)
    Rectangleposx.append(posx2)
    Rectangleposy.append(posy2)def Phrasemusicale(
    x, y, z, px, py, h, t
):  # Choix des différente formes de base pour définir les phrases musicales
    if t == 0:  # rectangle dimensions 100%
        bpy.ops.mesh.primitive_cube_add(radius=0.5, location=(px, py, z))
        bpy.ops.transform.resize(value=(x, y, h))
    if t == 3:  # rectangle dimensions 100%2 pour plus de ratio
        bpy.ops.mesh.primitive_cube_add(radius=0.5, location=(px, py, z))
        bpy.ops.transform.resize(value=(x, y, h))
    if t == 6:  # cylindre dimension 50%
        bpy.ops.mesh.primitive_cylinder_add(radius=0.5, depth=1, location=(px, py, z))
        bpy.ops.transform.resize(value=(x / 2, y / 2, h))
    if t == 2:  # cylindre dimension 25% et décalé en x+
        bpy.ops.mesh.primitive_cylinder_add(radius=0.5, depth=1, location=(px, py, z))
        bpy.ops.transform.resize(value=(x / 8, y / 8, h))
    if t == 4:  # cylindre dimension 25% et décalé en x-
        bpy.ops.mesh.primitive_cylinder_add(radius=0.5, depth=1, location=(px, py, z))
        bpy.ops.transform.resize(value=(x / 8, y / 8, h))
    if t == 1:  # rectangle dimension 50%
        bpy.ops.mesh.primitive_cube_add(radius=0.5, location=(px, py, z))
        bpy.ops.transform.resize(value=(x / 6, y / 635, h))
    bpy.context.object.name = "Phrase" + str(z)  # nomenclature de la formeMusiciens = 40  # Nombre de musiciens désirés
Mesures = 40  # Longueur de la chanson
hauteur = 10 / Mesures  # hauteur des phrases
frame_num = 0  # animation
animation_speed = 1  # Vitesse de l'animation(Nombre de frames par niveau)
Temps_video = 20  # temps de la video en seconde
Phrases_Count = 53  # Nombres de phrases musicales
TransMin = 1  # Scale pour phrase musicale minimum
TransMax = 2  # Scale pour phrase musicale maximum
typemax = 4  # nombre de type de formes différentes
sens = True  # sens de départ d'aparitiin
seuilonoff = 5  # seuil% de chance de passer on/off
seuilmin = 30  # nombre de musicien actif max
seuilmax = 90  # nombre de musicien actif minbpy.context.scene.render.fps = Mesures / Temps_video  # frequence d'encodage
bpy.context.scene.frame_end = Mesures * animation_speed  # Nombre d'image autocalculé
bpy.context.scene.frame_step = animation_speed  # Vitesse d'image autocalculébpy.ops.mesh.primitive_plane_add(location=(0,0,-4.9)) #Ajout d’un socle pour recevoir les ombres bpy.ops.transform.resize(value= (100,100,0))
bpy.ops.object.lamp_add(
    type="SUN", location=(10, 10, 20)
)  # ajout du soleil et orientation
bpy.ops.transform.rotate(
    value=0.727953,
    axis=(0, 1, 0),
    constraint_axis=(False, True, False),
    constraint_orientation="GLOBAL",
    mirror=False,
    proportional="DISABLED",
    proportional_edit_falloff="SMOOTH",
    proportional_size=1,
    release_confirm=True,
    use_accurate=False,
)bpy.ops.transform.rotate(value=-0.727953, axis=(1, 0, 0), constraint_axis=(True, False, False), constraint_orientation=’GLOBAL’, mirror=False, proportional=’DISABLED’, proportional_edit_falloff=’SMOOTH’, proportional_size=1, release_confirm=True, use_accurate=False)
bpy.context.object.data.shadow_method = "RAY_SHADOW"Coordonees = []  # Position des musiciens
Statut = []  # Musiciens actifs, inactifs
Phrases_musicales_taille = []  # Phrases musciales_taille
Phrases_musicales_type = []  # Phrases musciales_type de forme
Phrases_musicales_Index = []  # position du musicien dans la liste des phrases muscialesfor i in range(0, Musiciens):
    max_x, max_y = max(Rectanglex), max(Rectangley)
    i = Rectanglex.index(max_x) if max_x > max_y else Rectangley.index(max_y)
    Division(Rectanglex[i], Rectangley[i], Rectangleposx[i], Rectangleposy[i], i)for i in range(
    Phrases_Count
):  # Crée un liste de phrases musicale de différent type et tailles
    Phrases_musicales_taille.append(random.uniform(TransMin, TransMax))
    Phrases_musicales_type.append(random.randint(0, typemax))for i in range(0, len(Rectanglex)):
    Statut.append(random.randint(0, 1))  # Commence actif ou inactif
    Phrases_musicales_Index.append(1)  # Commence par la 1ere phrase musicaleAPPLICATION
for z in range(0, Mesures):  # Pour autant de mesures(z)
    print("Mesure", z)
    var1 = Statut.count(1)  # Nombre de musiciens Actifs
    var2 = len(Statut)  # Nombre total de musiciens
    musicienactifs = var1 / var2 * 100  # % de musicien actif
    print(musicienactifs, "%", " actif")
    if musicienactifs < seuilmin:  # passe en mode ascendant
        sens = True
    if musicienactifs > seuilmax:  # passe en mode descendant
        sens = False
    for i in range(0, len(Rectanglex)):  # pour tous les musiciens un par un par étage
        if Statut[i] == 1:  # Si musicien actifs’arrete si musicien a fini les phrases
            if Phrases_musicales_Index[i] == Phrases_Count - 1:
                continue
            else:                Phrasemusicale(
                    Rectanglex[i],
                    Rectangley[i],
                    z * hauteur - 5,
                    Rectangleposx[i] - 5,
                    Rectangleposy[i] - 5,
                    hauteur,
                    Phrases_musicales_type[Phrases_musicales_Index[i]],
                )
                bpy.ops.transform.resize(
                    value=(
                        Phrases_musicales_taille[Phrases_musicales_Index[i]],
                        Phrases_musicales_taille[Phrases_musicales_Index[i]],
                        1,
                    )
                )                obj = bpy.context.active_objectkey as visible on the current frame
                obj.keyframe_insert("hide", frame=z * animation_speed)
                obj.keyframe_insert("hide_render", frame=z * animation_speed)hide it
                obj.hide = True
                obj.hide_render = Truekey as hidden on the previous frame
                obj.keyframe_insert(
                    "hide", frame=z * animation_speed - 1 * animation_speed
                )
                obj.keyframe_insert(
                    "hide_render", frame=z * animation_speed - 1 * animation_speed
                )key as hidden on the next frame obj.keyframe_insert(‘hide’,frame=z+1) obj.keyframe_insert(‘hide_render’,frame=z+1)
        if sens:  # si  ascendant
            if not Statut[i]:
                if random.randint(0, 100) <= seuilonoff:  # % de chance de passer actifprint(‘actif’)
                    Statut[i] = 1
        if not sens:si musicien actif
            if Statut[i]:
                if (
                    random.randint(0, 100) <= seuilonoff
                ):  # % de chance de passer inactifprint(‘inactif’)
                    Statut[i] = 0ne s’applique pas si le musicien a fini ses phrases
        if Phrases_musicales_Index[i] == Phrases_Count - 1:
            continue
        else:
            if Phrases_musicales_Index[i] >= 5:  # Si musicien au dessus de la 5e phrase
                Analyse = []
                for analysis in range(
                    3, 6
                ):  # analyse le nombre de musiciens sur les phrases situées trois index plus bas, et quatre index après
                    Analyse.append(
                        Phrases_musicales_Index.count(
                            Phrases_musicales_Index[i] - analysis
                        )
                    )print (Analyse)
                if (
                    Analyse.count(0) == 3
                ):  # s'il n'y en a plus, il peut passer au suivantprint(‘analyse ok’)
                    if (
                        random.randint(0, 100) < 60
                    ):  # Choix du musicien si il change de phrase musicale
                        Phrases_musicales_Index[i] = Phrases_musicales_Index[i] + 1print ( ‘phrase musicale+1’)
            if (
                Phrases_musicales_Index[i] < 5
            ):  # Les cinq premières phrases ne risque pas d'aller trop vite
                if (
                    random.randint(0, 100) < 70
                ):  # % de chance pour le musicien de changer de phrase musicale
                    Phrases_musicales_Index[i] = Phrases_musicales_Index[i] + 1print (Phrases_musicales_Index[i])